import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

import opennlp.tools.postag.POSModel;

import org.xml.sax.helpers.DefaultHandler;

public class WSD extends DefaultHandler {

  public static final boolean POS = true;

  public SenseInventory senseInv_;
  public static boolean doCollSmoothing = false;
  public static double lambda = 0.1;
  public static int COLL_NB_METHOD = 1;
  public static int COLL_CM_METHOD = 2;
  private String senseInvFile_;

  public static FileWriter testCSV;
  public static FileWriter trainCSV;

  public static final String regexLetterNumber = "[a-zA-Z0-9]";
  public static final String regexSeparator = "([\\?!(),\";/\\|`:])";
  public static final String regexClitics = "(:|-|'S|'D|'M|'LL|'RE|'VE|N'T|'s|'d|'m|'ll|'re|'ve|n't)";
  public static final List<String> abbrList = Arrays.asList("Co.", "Corp.",
      "vs.", "e.g.", "etc.", "ex.", "cf.", "eg.", "est.", "Dept.", "Mr.",
      "Jr.", "Ms.", "Mrs.", "Dr.", "Ph.D.", "U.S.", "U.K.", "Ltd.", "A.M.",
      "i.e.", "...");
  public static final String HEAD_START = "<head>";
  public static final String HEAD_END = "</head>";

  public WSD(String senseInvFile) {
    senseInvFile_ = senseInvFile;
    senseInv_ = new SenseInventory(senseInvFile_);
  }

  public SenseInventory getSenseInv() {
    return senseInv_;
  }

  public static void formatXMLfile(BufferedReader br, FileWriter out)
  throws IOException {
    String line;
    out.write("<ROOT>" + "\n");
    int i = 0;
    while ((line = br.readLine()) != null) {
      i++;
      line = line.replaceAll("&", "@amp;");
      if (line.contains("gloss=")) {
        int index1 = line.indexOf("gloss=") + 7;
        int index2 = line.lastIndexOf("\"");
        line = line.substring(0, index1)
        + line.substring(index1, index2).replace("\"", " ")
        + line.substring(index2);
        // System.out.println(line);
      }
      out.write(line.trim() + "\n");
    }
    out.write("</ROOT>" + "\n");
    out.close();
    br.close();
  }

  public static void main(String[] args) throws IOException {
    //    testCSV = new FileWriter("data/EnglishLS.CSV.test");
    //    trainCSV = new FileWriter("data/EnglishLS.CSV.train");

    if (args.length != 1) {
      System.err.println("Usage: WSD <mode>");
      System.exit(1);
    }

    String senseInvFile = "data/EnglishLS/EnglishLS.dictionary.mapping.xml";
    WSD wsdObject = new WSD(senseInvFile);
    System.out.println("Dictionary loaded successfully");

    File trainFile = new File("data"+File.separator+"EnglishLS"+File.separator+"EnglishLS.train");
    File posTrain = new File("data"+File.separator+"EnglishLS"+File.separator+"EnglishLS.train.pos");

    if(WSD.POS) {
      posTag(trainFile, posTrain);
      System.out.println("trained file with pos tags:" + posTrain);
    }
    else {
      posTrain = trainFile;
      System.out.println("trained file:" + posTrain);
    }


    File testFile = new File("data"+File.separator+"EnglishLS"+File.separator+"EnglishLS.test");
    File posTest = new File("data"+File.separator+"EnglishLS"+File.separator+"EnglishLS.test.pos");

    if(WSD.POS) {
      posTag(testFile, posTest);
      System.out.println("test file with pos tags:" + posTest);
    }
    else {
      posTest = testFile;
      System.out.println("test file:" + posTest);
    }
    //    String testFile = "data/EnglishLS/EnglishLS.Sample.test";

    Training trainModel = new Training(posTrain.getAbsolutePath());
    System.out.println("Model trained successfully");

    String mode = args[0];

    if (mode.equals("col_NB")) {
      String collNBOutputFile = "data/scorer/Coll.NB.Test.Output.key";
      TestingCollocation testingColl_NB = new TestingCollocation(posTest.getAbsolutePath(), collNBOutputFile, trainModel, COLL_NB_METHOD, wsdObject);
    } else if (mode.equals("col_CM")){
      String collCMOutputFile = "data/scorer/Coll.CM.Test.Output.key";
      TestingCollocation testingColl_CM = new TestingCollocation(posTest.getAbsolutePath(), collCMOutputFile, trainModel, COLL_CM_METHOD, wsdObject);
    } else if (mode.equals("bow")){
      String bowCMOutputFile = "data/scorer/Bow.CM.Output.key";
      TestingBagOfWords testingBow_CM = new TestingBagOfWords(posTest.getAbsolutePath(), bowCMOutputFile, trainModel);
      System.out.println("output written to:" + new File(bowCMOutputFile).getAbsolutePath());
    } else {
      System.err.println("Invalid mode. Valid modes are: col_NB | col_CM | bow");
      System.exit(1);
    }

    System.out.println("TESTING COMPLETE");

    //    WSD.testCSV.close();
    //    WSD.trainCSV.close();
  }

  @SuppressWarnings("deprecation")
  public static void posTag(File inFile, File outFile){
    DataInputStream dis;
    FileInputStream fis;
    //    String inputpath = "data"+File.separator+"EnglishLS"+File.separator+"EnglishLS.Sample.train";
    BufferedInputStream bis;
    try {
      String nea=null;
      InputStream modelIn1 = new FileInputStream("data/en-pos-maxent.bin");
      POSModel model= new POSModel(modelIn1);
      opennlp.tools.postag.POSTagger posModel = new opennlp.tools.postag.POSTaggerME(model);

      fis = new FileInputStream(inFile);
      bis = new BufferedInputStream(fis);
      dis = new DataInputStream(bis);
      String str =null;
      StringBuilder build = new StringBuilder();
      BufferedWriter writer = new BufferedWriter(new FileWriter(outFile));
      String temp =null;
      boolean context=false;
      while((str = dis.readLine()) != null){
        //        build.append(str);
        if(!context && str.equalsIgnoreCase("<context>"))
          context = true;
        else if(!str.equalsIgnoreCase("</context>") && context) {
          int indexOf = str.indexOf(HEAD_START);
          if(indexOf >= 0) {
            int indexOf2 = str.indexOf(HEAD_END);
            temp = str.substring(0, indexOf) + str.substring(indexOf2+HEAD_END.length());
          }
          else
            temp = str;
          temp = posModel.tag(temp);
          writer.write(temp+"\n");
        }
        else if(str.equalsIgnoreCase("</context>")/* && context*/)
          context = false;
        else {
          writer.write(str+"\n");
        }
      }

      writer.flush();
      writer.close();

    }
    catch (Exception e) {
      System.out.println(e);
    }
  }
}
